<?php
/**
 * This file is part of the Zhan Framework (http://zhan.com)
 * Copyright © 2015 Zhan, Inc. (http://zhan.com)
 */

namespace Zhan\Foundation;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\HttpKernel\TerminableInterface;
use Zhan\Config\Config;
use Zhan\Container\Container;
use Zhan\Event\EventServiceProvider;
use Zhan\Exception\ExceptionServiceProvider;
use Zhan\Routing\RouteServiceProvider;

class Application extends Container implements HttpKernelInterface, TerminableInterface {

    /**
     * 构造函数
     * @param string $environment
     * @param bool $debug
     */
    public function __construct($environment = 'prod', $debug = true)
    {
        parent::__construct();
        $this['env'] = $environment;
        $this['debug'] = $debug;
        $this['request'] = Request::createFromGlobals();
    }

    /**
     * 将基础服务注册到容器中
     */
    public function registerBaseServiceProviders()
    {
        $this->registerEventServiceProvider();
        $this->registerExceptionServiceProvider();
        $this->registerRouteServiceProvider();
    }

    /**
     * 注册Event服务
     */
    public function registerEventServiceProvider()
    {
        $this->register(new EventServiceProvider($this));
    }

    /**
     * 注册Exception服务
     */
    public function registerExceptionServiceProvider()
    {
        $this->register(new ExceptionServiceProvider($this));
    }

    /**
     * 注册Route服务
     */
    public function registerRouteServiceProvider()
    {
        $this->register(new RouteServiceProvider($this));
    }

    /**
     * 注册提供的服务
     * @param Application $app
     * @param $providers
     */
    public function registerServiceProviders(Application $app, $providers)
    {
        foreach((array)$providers as $provider) {
            $this->register(new $provider($app));
        }
    }

    /**
     * 绑定框架基础目录
     * @param array $paths
     */
    public function bindFrameworkPaths(array $paths)
    {
        $this['path'] = realpath($paths['base']);
        unset($paths['base']);
        foreach($paths as $key => $value) {
            $this['path.'.$key] = realpath($value);
        }
    }

    /**
     * 获取配置集合
     */
    public function loadConfigParams()
    {
        $this['config'] = Config::load($this['path.config']);
    }

    /**
     * 运行应用程序
     * @param Request $request
     */
    public function run(Request $request = null)
    {
        if (null === $request) {
            $request = $this['request']?: Request::createFromGlobals();
        }

        $response = $this->handle($request)->send();
        $this->terminate($request, $response);
    }

    /**
     * Handles a Request to convert it to a Response.
     *
     * When $catch is true, the implementation must catch all exceptions
     * and do its best to convert them to a Response instance.
     *
     * @param Request $request A Request instance
     * @param int $type The type of the request
     *                         (one of HttpKernelInterface::MASTER_REQUEST or HttpKernelInterface::SUB_REQUEST)
     * @param bool $catch Whether to catch exceptions or not
     *
     * @return Response A Response instance
     *
     * @throws \Exception When an Exception occurs during processing
     *
     * @api
     */
    public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true)
    {
        if ($this->booted === false) {
            $this->boot();
        }
        return $this['http_kernel']->handle($request, $type, $catch);
    }

    /**
     * Terminates a request/response cycle.
     *
     * Should be called after sending the response and before shutting down the kernel.
     *
     * @param Request $request A Request instance
     * @param Response $response A Response instance
     *
     * @api
     */
    public function terminate(Request $request, Response $response)
    {
        $this['http_kernel']->terminate($request, $response);
    }
}